home *** CD-ROM | disk | FTP | other *** search
/ Emulator Universe CD / emulatoruniversecd1998.iso / CPC / Utils / CpcFile System / UI.C < prev    next >
Encoding:
C/C++ Source or Header  |  1996-02-08  |  38.8 KB  |  1,746 lines

  1.  
  2. /*                <<<<Last Modified: Thu Feb 08 15:08:45 1996>>>>
  3. ------------------------------------------------------------------------------
  4.  
  5.     =====
  6.     CPCfs  --   u i . c  --  Main program, and Text Interface
  7.     =====
  8.  
  9.     Version 0.85                    (c) February '96 by Derik van Zuetphen
  10. ------------------------------------------------------------------------------
  11. */
  12.  
  13.  
  14. #include "cpcfs.h"
  15.  
  16.  
  17.  
  18. /*********************************************************************
  19.                 Auxilaries
  20.  *********************************************************************/
  21.  
  22. int cmd_error (const char *msg) {
  23. /*  ^^^^^^^^^ */
  24.     return errorf(FALSE,"Use: %s",msg);
  25. }
  26.  
  27.  
  28. int    saved_fo, saved_mo;
  29.  
  30. void set_force_mode(int fo, int mo) {
  31. /*   ^^^^^^^^^^^^^^
  32. Save global <force> and <mode> and set them to <fo> and <mo> (unless 9999)*/
  33.     saved_fo = force;
  34.     saved_mo = mode;
  35.     if (fo!=9999) force = fo;
  36.     if (mo!=9999) mode = mo;
  37. }
  38.  
  39. void restore_force_mode() {
  40. /*   ^^^^^^^^^^^^^^^^^^ */
  41.     force = saved_fo;
  42.     mode = saved_mo;
  43. }
  44.  
  45.  
  46. /* Relationship between <optind> and <nbof_args>:
  47.   if (optind > nbof_args)     no non-option
  48.   if (optind == nbof_args)    exactly one non-option arg[optind]
  49.   if (optind < nbof_args)    non-options at arg[optind..nbof_args]
  50. */
  51.  
  52. #define REMAINING_ARGS (nbof_args-optind+1)
  53.  
  54. /*********************************************************************
  55.                 Commands
  56.  *********************************************************************/
  57.  
  58. int cmd_attrib() {
  59. /*  ^^^^^^^^^^ */
  60. int    set_mask = 0;
  61. int    reset_mask = 0;
  62. int    mask;
  63. bool     set;
  64. int    i;
  65. char    *pattern;
  66. const char errmsg[] = "ATTRIB <attribute>... <cpm-filespec>...";
  67. int    first_file = 0;        /* 0 = reading attributes, >0 files found */
  68.  
  69.     if (nbof_args==0) return cmd_error(errmsg);
  70.  
  71.     for (i=1;i<=nbof_args;i++) {
  72.         if (first_file == 0) {
  73.             if (arg[i][0]=='-') {
  74.                 if (parse_attr(arg[i]+1,&mask,&set)) {
  75.                     return errorf(FALSE,
  76.                       "Illegal attribute \"%s\"",arg[i]);
  77.                 }
  78.                 if (set)    set_mask |= mask;
  79.                 else        reset_mask |= mask;
  80.             } else {
  81.                 first_file = i;
  82.             }
  83.         } else {
  84.             if (arg[i][0]=='-')
  85.                 return errorf(FALSE,
  86.                     "FIRST attributes, THEN filenames");
  87.         }
  88.     }
  89.  
  90.     for (i=first_file;i<=nbof_args;i++) {
  91.         pattern = arg[i];
  92.         if (change_attrib(pattern,set_mask,reset_mask))
  93.             return 0;
  94.     }
  95.  
  96.     return 0;
  97. }
  98.  
  99.  
  100. int cmd_close() {
  101. /*  ^^^^^^^^^ */
  102.     if (nbof_args!=0)     return cmd_error("CLOSE");
  103.  
  104.     close_image();
  105.     return 0;
  106. }
  107.  
  108.  
  109. int cmd_cls() {
  110. /*  ^^^^^^^ */
  111.     if (nbof_args!=0)     return cmd_error("CLS");
  112.  
  113.     clrscr();
  114.     return 0;
  115. }
  116.  
  117.  
  118. int cmd_comment() {
  119. /*  ^^^^^^^^^^^ */
  120. int    i;
  121. time_t    now;
  122. const char original_text[] = "EMU Disk-File\r\nDisk-Info\r\n";
  123. char buf[256]; /* 3 lines should be enough */
  124. const char errmsg[] = "COMMENT [ -d | -n | <string> ]";
  125.  
  126.     if (inactive()) return -1;
  127.     if (nbof_args==0) {
  128.         printm(0,"Comment is \"");
  129.         for (i=0;i<40;i++) {
  130.             if (*(disk_header.tag+8+i)==0) break;
  131.             putcharm(0,*(disk_header.tag+8+i));
  132.         }
  133.         printm(0,"\"\n");
  134.         return 0;
  135.     }
  136.  
  137.     if (nbof_args!=1) return cmd_error(errmsg);
  138.     
  139.     if (arg[1][0]=='-') {
  140.         switch (tolower(arg[1][1])) {
  141.         case 'd':
  142.             comment_image(original_text);
  143.             break;
  144.         case 'n':
  145.             now = time(NULL);
  146.             strcpy(buf,"EMU / ");    /* 6 bytes */
  147.             strftime(buf+6,20,"%d %b %y %H:%M",localtime(&now));
  148.             buf[26]=0;
  149.             comment_image(buf);
  150.             break;
  151.         default:  return cmd_error(errmsg);
  152.         }
  153.     } else {
  154.         expand_percent(arg[1],buf,256);
  155.         comment_image(buf);
  156.     }
  157.     return 0;
  158. }
  159.  
  160.  
  161. int cmd_copy() {
  162. /*  ^^^^^^^^
  163. Copies one or more files to another file or in another user.
  164. */
  165.  
  166. int    trg_user;
  167. int    i;
  168. char    root[INPUTLEN], ext[INPUTLEN];
  169.  
  170. const char errmsg[] = "\tCOPY [-f | -t | -b] <form-cpmname> <to-cpmname>\n"
  171.               "\tCOPY [-f | -t | -b] <form-cpmspec>.. <userarea>";
  172. int    local_force, local_mode;
  173. char    optchar;
  174.  
  175.     if (inactive()) return 0;
  176.     if (nbof_args==0)
  177.         return cmd_error(errmsg);
  178.  
  179. /* parse options */
  180.     local_force = force;
  181.     local_mode = mode;
  182.     opterr = 0;    /* no errormessages in getopt */
  183.     optind = FIRST_OPTIND;
  184.     while ((optchar=getopt(nbof_args+1,arg,"ftb"))!= EOF) {
  185.         switch (optchar) {
  186.         case 'f':    local_force = TRUE;    break;
  187.         case 't':    local_mode = M_TEXT;    break;
  188.         case 'b':    local_mode = M_BIN;    break;
  189.         case '?':    return cmd_error(errmsg);
  190.         }
  191.     }
  192.     if (REMAINING_ARGS < 2)
  193.         return cmd_error(errmsg);
  194.  
  195.     set_force_mode(local_force,local_mode);
  196.  
  197.     parse_cpm_filename(arg[nbof_args],&trg_user,root,ext);
  198.     if (*root==0) {
  199.         if (trg_user==-1) trg_user = cur_user;
  200.         if (trg_user==-2)
  201.             return errorf(FALSE,"No wildcards allowed in user");
  202.         for (i=optind;i<nbof_args;i++) {
  203.             copy_wild(arg[i],trg_user);
  204.         }
  205.     } else {
  206.         if (REMAINING_ARGS!=2) return cmd_error(errmsg);
  207.         upper(arg[optind]);
  208.         copy_file(arg[optind],arg[optind+1]);
  209.     }    
  210.  
  211.     restore_force_mode();
  212.     return 0;
  213. }
  214.  
  215.  
  216. int cmd_dir() {
  217. /*  ^^^^^^^ */
  218. char    pattern[INPUTLEN] = "";
  219. int    what=DIR_DOUBLE;    /* see DIR_* in cpcfs.h */
  220. int    how=DIR_SORT;
  221. char    optchar;
  222. const char errmsg[] = "DIR [-l | -a | -w] [-u] [<cpm-filespec>]";
  223.  
  224.     if (inactive()) return 0;
  225.  
  226. /* parse options */
  227.     opterr = 0;    /* no errormessages in getopt */
  228.     optind = FIRST_OPTIND;
  229.     while ((optchar=getopt(nbof_args+1,arg,"awlu"))!= EOF) {
  230.         switch (optchar) {
  231.         case 'a':    what = DIR_AMSHEAD;    break;
  232.         case 'l':    what = DIR_LONG;    break;
  233.         case 'w':    what = DIR_WIDE;    break;
  234.         case 'u':    how &= ~DIR_SORT;    break;
  235.         case '?':    return cmd_error(errmsg);
  236.         }
  237.     }
  238.  
  239.     if (REMAINING_ARGS==0)    strcpy(pattern,"*.*");
  240.     if (REMAINING_ARGS==1)    strcpy(pattern,arg[optind]);
  241.     if (REMAINING_ARGS>1)    return cmd_error(errmsg);
  242.  
  243.     dir(pattern,what|how);
  244.     return 0;
  245. }
  246.  
  247.  
  248. int cmd_dira() {
  249. /*  ^^^^^^^^ */
  250.     execute_cmd("dump -d");
  251.     printm(1,"\nDIRA will be obsolete in future versions! "
  252.          "Use DUMP -D instead!\n");
  253.     return 0;
  254. }
  255.  
  256.  
  257. int cmd_dpb() {
  258. /*  ^^^^^^^ */
  259.     if (inactive())    return 1;
  260.     if (nbof_args!=0)    return cmd_error("DPB");
  261.  
  262.     printm(0,"Standard Disk Parameter Block:\n");
  263.     printm(0,"%s\n",repstr(hori,79));    
  264.     
  265.     printm(0,"SPT = 0x%-2X = %-3u   \trecords per track\n",
  266.         dpb->SPT,dpb->SPT);
  267.         printm(0,"BSH = 0x%1X = %-3u   \t2^BSH = records/block \n",
  268.         dpb->BSH,dpb->BSH);
  269.         printm(0,"BLM = 0x%1X = %-3u   \tBLM+1 = records/block \n",
  270.         dpb->BLM,dpb->BLM);
  271.     printm(0,"EXM = 0x%1X = %-3u   \tEXM+1 = extents/entry\n",
  272.         dpb->EXM,dpb->EXM);
  273.     printm(0,"DSM = 0x%-2X = %-3u   \tDSM+1 = total number of blocks\n",
  274.         dpb->DSM,dpb->DSM);
  275.     printm(0,"DRM = 0x%-2X = %-3u   \tDRM+1 = entries/directory\n",
  276.         dpb->DRM,dpb->DRM);
  277.     printm(0,"AL0 = 0x%1X = %-3u   \tfirst eight bit of allocation map\n",
  278.         dpb->AL0,dpb->AL0);
  279.     printm(0,"AL1 = 0x%1X = %-3u   \tsecond eight bit of allocation map\n",
  280.         dpb->AL1,dpb->AL1);
  281.     printm(0,"CKS = 0x%-2X = %-3u   \trecords/directory \n",
  282.         dpb->CKS,dpb->CKS);
  283.     printm(0,"OFS = 0x%-2X = %-3u   \treserved tracks for system (offset)\n",
  284.         dpb->OFS,dpb->OFS);
  285.  
  286.     putcharm(0,10);
  287.     printm(0,"Additional info:\n");
  288.     printm(0,"%s\n",repstr(hori,79));
  289.  
  290.     printm(0,"Heads = %d, ",dpb->HDS);
  291.     printm(0,"Tracks = %d, ",dpb->TRKS);
  292.     printm(0,"Sectors = %d\n",dpb->SECS);
  293.     printm(0,"Number of first sector = 0x%-2X\n",dpb->SEC1);
  294.     printm(0,"Bytes/sector           = %d\n",dpb->BPS);
  295.     printm(0,"Bytes/blocks           = %d\n",dpb->BLS);
  296.     printm(0,"Blocks/directory       = %d\n",dpb->DBL);
  297.  
  298.     return 0;
  299. }
  300.  
  301.  
  302. int cmd_dump() {
  303. /*  ^^^^^^^^ */
  304.  
  305. int    blk[2], hd[2], trk[2], sec[2];
  306. int    what=0;    /* 0=blkdump, 1=secdump, 2=dirdump, 3=map */
  307. int    how=1;    /* 0=on stdout, 1=on pager, 2=on file */
  308. int    ind=0;
  309. char    name[INPUTLEN] = "";
  310. char    optchar;
  311. FILE    *file;
  312. int    i,j,k;
  313. const char errmsg[] = "DUMP (-d | -m | (-b#|-h#|-t#|-s#|-1|-2)... ) "
  314.                         "[-f<dos-filename> | -c] ";
  315.  
  316.     if (inactive()) return 0;
  317.     if (nbof_args==0)    return cmd_error(errmsg);
  318.  
  319.     blk[0] = hd[0] = trk[0] = sec[0] = 0;
  320.     blk[1] = hd[1] = trk[1] = sec[1] = -1;
  321.  
  322.  
  323. /* parse options */
  324.     opterr = 0;    /* no errormessages in getopt */
  325.     optind = FIRST_OPTIND;
  326.     while ((optchar=getopt(nbof_args+1,arg,"b:h:t:s:f:cdm12"))!= EOF) {
  327.         switch (optchar) {
  328.         case 'b':    blk[ind]=atoxi(optarg);    what=0;    break;
  329.         case 'h':    hd[ind]=atoxi(optarg);    what=1;    break;
  330.         case 't':    trk[ind]=atoxi(optarg);    what=1;    break;
  331.         case 's':    sec[ind]=atoxi(optarg);    what=1;    break;
  332.         case 'f':    strcpy(name,optarg);    how=2;    break;
  333.         case 'c':    how=0;    break;
  334.         case 'd':    what=2;    break;
  335.         case 'm':    what=3;    break;
  336.         case '1':    ind=0;    break;
  337.         case '2':    ind=1;    break;
  338.         case ':':
  339.         case '?':    return cmd_error(errmsg);
  340.         }
  341.     }
  342.  
  343.     if (REMAINING_ARGS>0)
  344.         return cmd_error(errmsg);
  345.  
  346. /* prepare the output medium */
  347.     switch (how) {
  348.     case 0:        /* stdout */
  349.         file=stdout;/*fdopen(1,"w");*/
  350.         break;
  351.     case 1:        /* pager */
  352.         tmp_nam(name);
  353.         file = fopen(name,"w");        
  354.             if (file==NULL) {
  355.             return errorf(TRUE,"Cannot open temporary file \"%s\" "
  356.                             "for writing ",name);
  357.         }
  358.     case 2:        /* file */
  359.         file = fopen(name,"w");
  360.             if (file==NULL) {
  361.             return errorf(TRUE,"Cannot open \"%s\" for writing ",
  362.                                     name);
  363.         }
  364.     }
  365.     
  366. /* adjust addresses */
  367.     blk[0] = max(0,blk[0]);
  368.     hd[0]  = max(0,hd[0]);
  369.     trk[0] = max(0,trk[0]);
  370.     sec[0] = max(0,sec[0]);
  371.  
  372.     blk[1] = min(dpb->DSM,blk[1]);
  373.     hd[1]  = min(dpb->HDS-1,hd[1]);
  374.     trk[1] = min(dpb->TRKS-1,trk[1]);
  375.     sec[1] = min(dpb->SECS-1,sec[1]);
  376.     
  377.     if (blk[1]==-1) blk[1]=blk[0];
  378.     if (hd[1]==-1)  hd[1] =hd[0];    
  379.     if (trk[1]==-1)
  380.         if (hd[1]==hd[0]) trk[1]=trk[0];
  381.         else          trk[1]=dpb->TRKS-1;
  382.     if (sec[1]==-1)
  383.         if (trk[1]==trk[0]) sec[1]=sec[0];
  384.         else            sec[1]=dpb->SECS-1;
  385.     
  386. /* do the output */
  387.     switch (what) {
  388.     case 0:        /* blkdump */
  389.         for (i=blk[0];i<=blk[1];i++) {
  390.             if (Break_Wish) {
  391.                 if (how!=0) fclose(file);
  392.                 do_break();
  393.             }
  394.             if (dump(file,i,-1,-1,-1)) break;
  395.         }
  396.         break;
  397.     case 1:        /* secdump */
  398.         i=hd[0]; j=trk[0]; k=sec[0];
  399.         for (;;) {
  400.             if (Break_Wish) {
  401.                 if (how!=0) fclose(file);
  402.                 do_break();
  403.             }
  404.             if (dump(file,-1,i,j,k)) break;
  405.             if (i==hd[1] && j==trk[1] && k==sec[1]) break;
  406.             next_sector(&i,&j,&k);
  407.         }
  408.         break;
  409.     case 2:        /* dirdump */
  410.         dumpdir(file);
  411.         break;
  412.     case 3:        /* map */
  413.         map(file);
  414.         break;
  415.     }
  416.     
  417.     fflush(file);
  418.     if (how!=0) fclose(file);    /* do not close stdout */
  419.     if (how==1) {
  420.         if (pager(name)) {
  421.             unlink(name);
  422.             return errorf(TRUE,"DUMP");
  423.         }
  424.         unlink(name);
  425.     }
  426.     
  427.     return 0;
  428. }
  429.  
  430.  
  431. int cmd_echo () {
  432. /*  ^^^^^^^^ */
  433.     if (nbof_args>1) {
  434.         return cmd_error("ECHO <string>");
  435.     }
  436.  
  437.     if (nbof_args == 1)  {
  438.         echom(0,arg[1]);    
  439.     }
  440.     putcharm(0,10);
  441.     return 0;
  442. }
  443.  
  444.  
  445. int cmd_era() {
  446. /*  ^^^^^^^ */
  447. long    freed = 0;
  448. int    files = 0;
  449. int    i;
  450. char    optchar;
  451. int    local_force;
  452. const char errmsg[] = "(DEL|ERA) [-f] <cpm-filespec>...";
  453.  
  454.     if (inactive()) return 0;
  455.     if (nbof_args==0)     return cmd_error(errmsg);
  456.  
  457. /* parse options */
  458.     local_force = force;
  459.     opterr = 0;    /* no errormessages in getopt */
  460.     optind = FIRST_OPTIND;
  461.     while ((optchar=getopt(nbof_args+1,arg,"f"))!= EOF) {
  462.         switch (optchar) {
  463.         case 'f':    local_force = TRUE;    break;
  464.         case '?':    return cmd_error(errmsg);
  465.         }
  466.     }
  467.  
  468.     if (REMAINING_ARGS==0)
  469.         return cmd_error(errmsg);
  470.  
  471.     set_force_mode(local_force,9999);
  472.     for (i=optind;i<=nbof_args;i++) {
  473.         freed += delete(FALSE,arg[i]);
  474.         files++;    /* actually filespecs, not files!! */
  475.     }
  476.     printm(2,"Total: %ld Bytes\n",freed);
  477.  
  478.     restore_force_mode();
  479.     put_directory();
  480.     return 0;
  481. }
  482.  
  483.  
  484. int cmd_exit() {
  485. /*  ^^^^^^^ */
  486.     close_image();
  487.     exit(0); return 0;
  488. }
  489.  
  490.  
  491. int cmd_force() {
  492. /*  ^^^^^^^^^ */
  493.     if (nbof_args > 0 ) return cmd_error("FORCE");
  494.  
  495.     force = !force;
  496.  
  497.     printm(2,"Force is switched ");
  498.     if (force) {printm(2,"*ON*!\n");}
  499.     else       {printm(2,"-off-!\n");}
  500.  
  501.     return 0;
  502. }
  503.  
  504.  
  505. int cmd_get() {
  506. /*  ^^^^^^^ */
  507. char    trg[INPUTLEN];
  508. int    user;
  509. int    drive;
  510. char    path[INPUTLEN];
  511. char    root[INPUTLEN];
  512. char    ext[INPUTLEN];
  513. long    done;
  514. char    *src;
  515. int    i;
  516. const char errmsg[] = "\tGET [-f | -t | -b] <cpm-filename> [<dos-filename>]\n"
  517.               "\tGET [-f | -t | -b] <cpm-filename>... <dos-path>";
  518. int    local_force, local_mode;
  519. char    optchar;
  520.  
  521.     if (inactive()) return 0;
  522.     if (nbof_args==0) {
  523.         return cmd_error(errmsg);
  524.     }
  525.  
  526. /* parse options */
  527.     local_force = force;
  528.     local_mode = mode;
  529.     opterr = 0;    /* no errormessages in getopt */
  530.     optind = FIRST_OPTIND;
  531.     while ((optchar=getopt(nbof_args+1,arg,"ftb"))!= EOF) {
  532.         switch (optchar) {
  533.         case 'f':    local_force = TRUE;    break;
  534.         case 't':    local_mode = M_TEXT;    break;
  535.         case 'b':    local_mode = M_BIN;    break;
  536.         case '?':    return cmd_error(errmsg);
  537.         }
  538.     }
  539.     if (REMAINING_ARGS==0)
  540.         return cmd_error(errmsg);
  541.  
  542.     set_force_mode(local_force,local_mode);
  543.  
  544. /* last arg end with backslash */
  545.     if (REMAINING_ARGS > 1
  546.         && arg[nbof_args][strlen(arg[nbof_args])-1]==DIRSEPARATOR) {
  547.         parse_filename(arg[nbof_args],&drive,path,root,ext);
  548.         if (*root) {
  549.             cmd_error(errmsg);
  550.             restore_force_mode();
  551.             return 1;
  552.         }
  553.         for (i=optind;i<nbof_args;i++) {
  554.             parse_cpm_filename(arg[i],&user,root,ext);        
  555.             build_cpm_name(src,user,root,ext);
  556.  
  557.             if (drive>0)    {trg[0] = drive+'@'; trg[1]=0;}
  558.             else        {trg[0]=0;}
  559.             strcat(trg,path);
  560.             strcat(trg,root);
  561.             if (*ext)    {strcat(trg,"."); strcat(trg,ext);}
  562.         
  563.             printm(2,"Getting \"%s\": ",src);
  564.             done = get (src,trg);
  565.             if (done>=0)
  566.                 printm(2,"%ld Bytes\n",done);
  567.             else
  568.                 printm(2,"[skipped]\n");
  569.         }                    
  570.         
  571.     } else {    /* one or two args */
  572.         src = arg[optind];
  573.         if (REMAINING_ARGS==1) {
  574.             parse_cpm_filename(src,&user,trg,ext);
  575.             if (ext[0]!=0) {
  576.                 strcat(trg,".");
  577.                 strcat(trg,ext);
  578.             }
  579.             lower(trg);
  580.         } else
  581.             strcpy(trg,arg[optind+1]);
  582.     
  583.         printm(2,"Getting \"%s\": ",src);
  584.         done = get (src,trg);
  585.         if (done>=0)
  586.             printm(2,"%ld Bytes\n",done);
  587.         else
  588.             printm(2,"[skipped]\n");
  589.     }
  590.  
  591.  
  592.     restore_force_mode();
  593.     return 0;
  594. }
  595.  
  596.  
  597. int cmd_help() {
  598. /*  ^^^^^^^^
  599. Writes a part of CPCFS.HLP to stdout.
  600. */
  601. char    topic[20];
  602. char    line[INPUTLEN];
  603. FILE    *file;
  604. bool    found = FALSE;
  605. bool    ok = FALSE;
  606.  
  607.     if (nbof_args>1) return cmd_error("HELP or HELP <topic>");
  608.     else if (nbof_args==0) strcpy(topic,"~nothing~");
  609.     else {
  610.         strcpy(topic,"~");
  611.         strcat(topic,arg[1]);
  612.         strcat(topic,"~");
  613.     }
  614.     lower(topic);
  615.  
  616.     strcpy(line,installpath);
  617.     strcat(line,HELPFILE);
  618.     file = fopen(line,"r");
  619.     if (file==NULL) return errorf(TRUE,"I cannot read \"%s\"",line);
  620.  
  621. /* Scans for a line with ~<topic>~, puts the lines until the next ~ is reached */
  622.  
  623.     while (fgets(line,INPUTLEN,file)!=NULL) {
  624.         if (found && line[0]!='~') {printm(0,"\r%s",line); ok = TRUE;}
  625.         if (found && line[0]=='~') {found=FALSE; continue;}
  626.         if (!found&& line[0]!='~') continue;
  627.         if (!found&& line[0]=='~') found = (strstr(line,topic)!=NULL);
  628.     }
  629.     
  630.     fclose(file);
  631.  
  632.     if (!ok) {
  633.         topic[0]='"';
  634.         topic[strlen(topic)-1]='"';
  635.         return errorf(FALSE,"No help for %s",topic);
  636.     }
  637.     return 0;
  638. }
  639.  
  640.  
  641. int cmd_lcd() {
  642. /*  ^^^^^^^ */
  643. char    buf[256];
  644. int    err;
  645. #if DOS
  646. char    *p;
  647. #endif
  648.  
  649.     if (nbof_args==0)
  650.         printm(0,"Working directory is \"%s\"\n",getwd(buf));
  651.     else if (nbof_args>1) {
  652.         return cmd_error("(CD|LCD) <dos-drive&directory>");
  653.     } else {
  654.     if (arg[1][strlen(arg[1])-1]==DIRSEPARATOR)
  655.         arg[1][strlen(arg[1])-1] = 0;
  656. #if DOS
  657.         if (arg[1][1]==':') {
  658.             setdisk(toupper(arg[1][0])-'A');
  659.             p=arg[1]+2;
  660.         } else
  661.             p=arg[1];
  662.         err = *p==0? 0 : chdir(p);
  663. #else
  664.         err = chdir(arg[1]);
  665. #endif
  666.         if (err) {
  667.             return errorf (FALSE,"I cannot cd to \"%s\"!",arg[1]);
  668.         }
  669.         printm(2,"Working directory is now \"%s\"\n",getwd(buf));
  670.     }
  671.     return 0;
  672. }
  673.  
  674.  
  675. int cmd_ldir() {
  676. /*  ^^^^^^^^ */
  677. char    buf[INPUTLEN];
  678. int    i;
  679.     *buf = 0;
  680.     strcat(buf,LDIRCOMMAND);
  681.     for (i=1;i<=nbof_args;i++) {
  682.         strcat(buf," ");
  683.         strcat(buf,arg[i]);
  684.     }
  685.     if (system (buf)) {
  686.         return errorf(TRUE,"Error executing \"%s\"",buf);
  687.     }
  688.     return 0;
  689. }
  690.  
  691.  
  692. int cmd_map() {
  693. /*  ^^^^^^^ */
  694.     execute_cmd("dump -m");
  695.     printm(1,"\nMAP will be obsolete in future versions! "
  696.          "Use DUMP -MB instead!\n");
  697.     return 0;
  698. }
  699.  
  700.  
  701. int cmd_mget() {
  702. /*  ^^^^^^^^ */
  703. char    src[INPUTLEN];
  704. char    trg[INPUTLEN];
  705. int    ent;
  706. int    i;
  707. int    files=0;
  708. long    done=0,
  709.     total=0;
  710. const char errmsg[] = "MGET [-f | -t | -b] <cpm-filespec>...";
  711. int    local_force, local_mode;
  712. char    optchar;
  713.  
  714.     if (nbof_args==0)     return cmd_error(errmsg);
  715.  
  716. /* parse options */
  717.     local_force = force;
  718.     local_mode = mode;
  719.     opterr = 0;    /* no errormessages in getopt */
  720.     optind = FIRST_OPTIND;
  721.     while ((optchar=getopt(nbof_args+1,arg,"ftb"))!= EOF) {
  722.         switch (optchar) {
  723.         case 'f':    local_force = TRUE;    break;
  724.         case 't':    local_mode = M_TEXT;    break;
  725.         case 'b':    local_mode = M_BIN;    break;
  726.         case '?':    return cmd_error(errmsg);
  727.         }
  728.     }
  729.     if (REMAINING_ARGS==0)
  730.         return cmd_error(errmsg);
  731.  
  732.     set_force_mode(local_force,local_mode);
  733.     
  734.     for (i=optind;i<=nbof_args;i++) {
  735.         ent = glob_cpm_file(arg[i]);
  736.         if (ent<0) {
  737.             return errorf(FALSE,"\"%s\" not found",arg[i]);
  738.             continue;
  739.         }
  740.         while (ent>=0) {
  741. /* prepare CP/M name */
  742.             sprintf(src,"%u:%s",directory[ent].user,
  743.                             directory[ent].name);
  744.  
  745. /* prepare DOS name */
  746.             strcpy(trg,(signed char*)directory[ent].name);
  747.             lower(trg);
  748.             if (trg[strlen(trg)-1]=='.') trg[strlen(trg)-1]=0;
  749.  
  750.             printm(2,"Getting \"%s\": ",src);
  751.             glob_env++;    /* <get> itself uses <glob_cpm_*> */
  752.             done = get(src,trg);
  753.             glob_env--;
  754.  
  755.             if (done>=0) {
  756.                 printm(2,"%ld Bytes\n",done);
  757.                 files++;
  758.                 total += done;
  759.             } else
  760.                 printm(2,"[skipped]\n");
  761.  
  762.             ent = glob_cpm_next();
  763.         }
  764.     } /* for i */
  765.  
  766.     printm(2,"Total: %ld Bytes, %d file%s\n", total, files, plural(files));
  767.     restore_force_mode();
  768.     return 0;
  769. }
  770.  
  771.  
  772. int cmd_mode() {
  773. /*  ^^^^^^^^ */
  774.     if (nbof_args == 0) {
  775.         printm(0,"Mode is %s\n",show_mode(mode));
  776.         return 0;
  777.     }
  778.     if (nbof_args> 1 ) {
  779.         return cmd_error("MODE bin | text | auto");
  780.     }
  781.  
  782.     switch (tolower(arg[1][0]))  {
  783.     case 'b':
  784.         mode = M_BIN;
  785.         break;
  786.     case 't':
  787.         mode = M_TEXT;
  788.         break;
  789.     case 'a':
  790.         mode = M_AUTO;
  791.         break;
  792.     default:
  793.         return errorf(FALSE,"Unrecognized mode \"%s\". "
  794.             "Valid are Auto, Bin, and Text; or A, B, T.\n",arg[1]);
  795.     }
  796.     printm(2,"Mode set to %s\n",show_mode(mode));
  797.     return 0;
  798. }
  799.  
  800.  
  801. int cmd_mput() {
  802. /*  ^^^^^^^^ */
  803. char    trg[13];
  804. char    *src;
  805. int    files;
  806. int    total_files = 0;
  807. long    done=0,
  808.     total=0;
  809. int    drive;
  810. char    path[INPUTLEN];
  811. char    rootname[INPUTLEN];
  812. char    extension[INPUTLEN];
  813. const char errmsg[] = "MPUT [-f | -t | -b] <dos-filespec>...";
  814. int    local_force, local_mode;
  815. char    optchar;
  816. int    i;
  817.  
  818.     if (inactive()) return 0;
  819.     if (nbof_args==0)  {
  820.         return cmd_error(errmsg);
  821.     }
  822.  
  823. /* parse options */
  824.     local_force = force;
  825.     local_mode = mode;
  826.     opterr = 0;    /* no errormessages in getopt */
  827.     optind = FIRST_OPTIND;
  828.     while ((optchar=getopt(nbof_args+1,arg,"ftb"))!= EOF) {
  829.         switch (optchar) {
  830.         case 'f':    local_force = TRUE;    break;
  831.         case 't':    local_mode = M_TEXT;    break;
  832.         case 'b':    local_mode = M_BIN;    break;
  833.         case '?':    return cmd_error(errmsg);
  834.         }
  835.     }
  836.     if (REMAINING_ARGS==0)
  837.         return cmd_error(errmsg);
  838.  
  839.     set_force_mode(local_force,local_mode);
  840.  
  841.  
  842.     for (i=optind;i<=nbof_args;i++) {
  843.         src = glob_file(arg[i]);
  844.         files = 0;
  845.         while (src!=NULL) {
  846.             parse_filename(src,&drive,path,rootname,extension);
  847.             strcpy(trg,rootname);
  848.             if (*extension) {
  849.                 strcat(trg,".");
  850.                 strcat(trg,extension);
  851.             }
  852.     
  853.             printm(2,"Putting \"%s\": ",src);
  854.             done = put(src,trg);
  855.             if (done>=0) {
  856.                 printm(2,"%ld Bytes\n",done);
  857.                 total += done;
  858.                 files++;
  859.             } else if (done==-1)
  860.                 printm(2,"[skipped]\n");
  861.             else {    /* done==-2 */
  862.                 printm(2,"[aborted]\n");
  863.                 restore_force_mode();
  864.                 return 1;
  865.             }
  866.  
  867.             src=glob_next();
  868.         }
  869.         if (files==0)  {
  870.             printm(1,"\"%s\" not found!\n",arg[i]);
  871.         } else {
  872.             total_files += files;
  873.         }
  874.  
  875.     } /* for i*/
  876.  
  877.     printm(2,"Total: %ld Bytes, %d file%s\n",total,total_files,
  878.                             plural(total_files));
  879.     restore_force_mode();
  880.     return 0;
  881. }
  882.  
  883.  
  884. int cmd_new() {
  885. /*  ^^^^^^^ */
  886. DPB_type *dpb;
  887. char    name[INPUTLEN];
  888. const char errmsg[] = "(NEW|FORMAT) [-s | -d | -i | -v]  <imagename>";
  889. char    optchar;
  890.  
  891.     if (nbof_args==0) {
  892.         return cmd_error(errmsg);
  893.     }
  894.  
  895. /* parse options */
  896.     opterr = 0;    /* no errormessages in getopt */
  897.     optind = FIRST_OPTIND;
  898.     dpb = &DPB_store[DATA_DPB];
  899.     while ((optchar=getopt(nbof_args+1,arg,"sdiv"))!= EOF) {
  900.         switch (optchar) {
  901.         case 's':    dpb = &DPB_store[SYSTEM_DPB]; break;
  902.         case 'd':    dpb = &DPB_store[DATA_DPB]; break;
  903.         case 'i':    dpb = &DPB_store[IBM_DPB]; break;
  904.         case 'v':    dpb = &DPB_store[VORTEX_DPB]; break;
  905.         case '?':    return cmd_error(errmsg);
  906.         }
  907.     }
  908.     if (REMAINING_ARGS!=1)
  909.         return cmd_error(errmsg);
  910.  
  911.     close_image();
  912.     strcpy(name,arg[optind]);
  913.     append_suffix(name,"dsk");
  914.  
  915.     if (access(name,F_OK)==0) {
  916.         if (Verb > 0) {
  917.             printm(1,"\"%s\" already exists! Overwrite? ",name);
  918.             if (!confirmed())  {
  919.                 return 0;
  920.             }
  921.         }
  922.     }
  923.  
  924.     if (format(name,dpb)) return 0;
  925.  
  926.     open_image(name);    /* reopen and initialize */
  927.     return 0;
  928. }
  929.  
  930.  
  931. int cmd_open() {
  932. /*  ^^^^^^^^ */
  933. char    buf[INPUTLEN];
  934.  
  935.  
  936.     if (nbof_args==0) {
  937.         if (*disk_header.tag)
  938.             printm(0,"Image in use is \"%s\"\n",imagename);
  939.         else
  940.             printm(0,"No Image loaded!\n");
  941.     }
  942.     else if (nbof_args>1) {
  943.         return cmd_error("OPEN <image-file>");
  944.     }
  945.     else {
  946.         strcpy(buf,arg[1]);
  947.         append_suffix(buf,"dsk");
  948.         open_image(buf);
  949.     }
  950.     return 0;
  951. }
  952.  
  953.  
  954. int cmd_page()  {
  955. /*  ^^^^^^^^ */
  956.     if (nbof_args>1)  return cmd_error("PAGE <number-of-lines>");
  957.  
  958.     if (nbof_args==0)
  959.         printm(0,"Page length is  %d\n",pagelen);
  960.     else {
  961.         pagelen = atoxi(arg[1]);
  962.         printm(2,"Page length set to %d\n",pagelen);
  963.     }
  964.     return 0;
  965. }
  966.  
  967.  
  968. int cmd_prompt() {
  969. /*  ^^^^^^^^^^ */
  970.     if (nbof_args == 0) {
  971.         printm(0,"Prompt is \"%s\"\n",prompt);
  972.         return 0;
  973.     }
  974.     if (nbof_args>1) {
  975.         return cmd_error("PROMPT <string>");
  976.     }
  977.  
  978.     strcpy(prompt,arg[1]);
  979.     return 0;
  980. }
  981.  
  982.  
  983. int cmd_put() {
  984. /*  ^^^^^^^ */
  985. char    trg[INPUTLEN];        /* CP/M name */
  986. long    done;
  987. int     drive;
  988. char    path[INPUTLEN];
  989. char    rootname[INPUTLEN];
  990. char    extension[INPUTLEN];
  991. const char errmsg[] = "\tPUT [-f | -t | -b] <dos-filename> [<cpm-filename>]\n"
  992.               "\tPUT [-f | -t | -b] <dos-filename> [<userarea>]\n";
  993. int    local_force, local_mode;
  994. char    optchar;
  995.  
  996.     if (inactive()) return 0;
  997.     if (nbof_args==0)  {
  998.         return cmd_error(errmsg);
  999.     }
  1000.  
  1001. /* parse options */
  1002.     local_force = force;
  1003.     local_mode = mode;
  1004.     opterr = 0;    /* no errormessages in getopt */
  1005.     optind = FIRST_OPTIND;
  1006.     while ((optchar=getopt(nbof_args+1,arg,"ftb"))!= EOF) {
  1007.         switch (optchar) {
  1008.         case 'f':    local_force = TRUE;    break;
  1009.         case 't':    local_mode = M_TEXT;    break;
  1010.         case 'b':    local_mode = M_BIN;    break;
  1011.         case '?':    return cmd_error(errmsg);
  1012.         }
  1013.     }
  1014.     if (REMAINING_ARGS>2 || REMAINING_ARGS==0)
  1015.         return cmd_error(errmsg);
  1016.  
  1017.     set_force_mode(local_force,local_mode);
  1018.  
  1019. /* build target name */
  1020.     parse_filename(arg[optind],&drive,path,rootname,extension);
  1021.     if (REMAINING_ARGS==1) {
  1022.         strcpy(trg,rootname);
  1023.         if (*extension) {
  1024.             strcat(trg,".");
  1025.             strcat(trg,extension);
  1026.         }
  1027.     } else if (arg[optind+1][strlen(arg[optind+1])-1]==':') {/* only user */
  1028.         strcpy(trg,arg[optind+1]);
  1029.         strcat(trg,rootname);
  1030.         if (*extension) {
  1031.             strcat(trg,".");
  1032.             strcat(trg,extension);
  1033.         }
  1034.     } else {
  1035.         strcpy(trg,arg[optind+1]);
  1036.     }
  1037.  
  1038.     printm(2,"Putting \"%s\": ",arg[optind]);
  1039.     done = put(arg[optind],trg);
  1040.     if (done>=0)
  1041.         printm(2,"%ld Bytes\n",done);
  1042.     else if (done==-1)
  1043.         printm(2,"[skipped]\n");
  1044.     else /* done==-2 */
  1045.         printm(2,"[aborted]\n");
  1046.     restore_force_mode();
  1047.     return 0;
  1048. }
  1049.  
  1050.  
  1051. int cmd_ren() {
  1052. /*  ^^^^^^^
  1053. Reanmes a file to another name or shift a lot of files to another user. */
  1054. int    i;
  1055. int    trg_user;
  1056. char    root[INPUTLEN], ext[INPUTLEN];
  1057.  
  1058. const char errmsg[] = "\tREN <from-cpm-filespec> <to-cpm-filespec>\n"
  1059.               "\tREN <from-cpm-filespec>... <userarea>";
  1060.  
  1061.     if (inactive()) return 0;
  1062.     if (nbof_args<2) {
  1063.         return cmd_error(errmsg);
  1064.     }
  1065.  
  1066.     parse_cpm_filename(arg[nbof_args],&trg_user,root,ext);
  1067.     if (*root==0) {
  1068.         if (trg_user==-1) trg_user = cur_user;        
  1069.         if (trg_user==-2)
  1070.             return errorf(FALSE,"No wildcards allowed in user");
  1071.         for (i=1;i<nbof_args;i++) {
  1072.             ren_wild(arg[i],trg_user);
  1073.         }
  1074.     } else {
  1075.         if (nbof_args!=2) return cmd_error(errmsg);
  1076.         ren_file(arg[1],arg[2]);
  1077.     }
  1078.  
  1079.     update_directory();
  1080.     put_directory();
  1081.     return 0;
  1082. }
  1083.  
  1084.  
  1085. int cmd_source() {
  1086. /*  ^^^^^^^^^^ */
  1087.  
  1088.     if (nbof_args!=1)     return cmd_error("SOURCE <dos-filename>");
  1089.     execute_file (arg[1]);
  1090.     return 0;
  1091. }
  1092.  
  1093.  
  1094. int cmd_spawn() {
  1095. /*  ^^^^^^^^^ */
  1096. char    *buf;
  1097. const char errmsg[] ="Error executing \"%s\"";
  1098.  
  1099.     if (nbof_args==0) {
  1100.         printm(3,"[EXIT to return to cpcfs]\n");
  1101.         if ((buf=getenv(SHELLVAR))==NULL) {
  1102.             save_path();
  1103.             if (system(SHELLDEFAULT)) {
  1104.                 return errorf(TRUE,errmsg,SHELLDEFAULT);
  1105.             }
  1106.             rest_path();
  1107.         } else {
  1108.             save_path();
  1109.             if (system (buf)) {
  1110.                 return errorf(TRUE,errmsg,buf);
  1111.             }
  1112.             rest_path();
  1113.         }
  1114.     } else {
  1115.         reparse(1);
  1116.         save_path();
  1117.         if (system(arg[1])) {
  1118.             return errorf(TRUE,errmsg,arg[1]);
  1119.         }
  1120.         rest_path();
  1121.     }
  1122.     if ((*disk_header.tag) && (access(full_imagename,R_OK))) {
  1123.         abandonimage();
  1124.         return -1;
  1125.     }
  1126.     return 0;
  1127. }
  1128.  
  1129.  
  1130. int cmd_stat() {
  1131. /*  ^^^^^^^^ */
  1132. char    buf[256];
  1133.     if (nbof_args!=0) return cmd_error("STAT");
  1134.  
  1135.     putcharm(0,10);
  1136.     if (*disk_header.tag) {
  1137.         printm(0,"Image File     : %s\n",imagename);
  1138.         printm(0,"Format         : %s\n",show_format(cur_format));
  1139.         putcharm(0,10);
  1140.         printm(0,"CP/M           : ");
  1141.         if (dpb->SYS) {
  1142.             printm(0,"Yes\n");
  1143.         } else {
  1144.             printm(0,"No");
  1145.             if (dpb->OFS > 0)
  1146.                 printm(0,", but %d track%s reserved\n",
  1147.                           dpb->OFS,plural(dpb->OFS));
  1148.             else
  1149.                 printm(0,"\n");
  1150.         }
  1151.         printm(0,"Current user   : %d\n",cur_user);
  1152.         putcharm(0,10);
  1153.  
  1154.         printm(0,"Capacity       : %d Blocks = %ld Bytes\n",
  1155.                 dpb->DSM+1, ((long)dpb->DSM+1)*dpb->BLS);
  1156.         printm(0,"Directory      : %d Block%s\n",
  1157.                        (dpb->DRM+1)*32/(dpb->BLS),
  1158.                 plural((dpb->DRM+1)*32/(dpb->BLS)));
  1159.         printm(0,"Allocated      : %d Block%s = %ld Bytes = %5.1f%%\n",
  1160.             allocated_blks, plural(allocated_blks),
  1161.             (long)allocated_blks*dpb->BLS, percentage);
  1162.         printm(0,"Free           : %d Block%s = %ld Bytes = %5.1f%%\n",
  1163.             free_blks, plural(free_blks),
  1164.             (long)free_blks*dpb->BLS, 100.0-percentage);
  1165.         putcharm(0,10);
  1166.     } else    {
  1167.         printm(0,"No image loaded!\n");
  1168.         putcharm(0,10);
  1169.     }
  1170.  
  1171.     printm(0,"Prompt=\"%s\";  ",prompt);
  1172.     printm(0,"Local directory=\"%s\"\n", getwd(buf));
  1173.     printm(0,"Verbosity=%d;  ",Verb);
  1174.     printm(0,"Page length=%d;  ",pagelen);
  1175.     printm(0,"Mode=%s;  ",show_mode(mode));
  1176.     printm(0,"Force=");
  1177.             if (force) printm(0,"*ON*"); else printm(0,"-off-");
  1178.     printm(0,"\n");
  1179.     putcharm(0,10);
  1180.  
  1181.     return 0;
  1182. }
  1183.  
  1184.  
  1185. int cmd_sysgen() {
  1186. /*  ^^^^^^^^^^ */
  1187.     if (inactive()) return 0;
  1188.     if (nbof_args!=1) return cmd_error("SYSGEN <dos-filename>");
  1189.  
  1190.     if (dpb->OFS == 0) {
  1191.         return errorf(FALSE,"No system tracks reserved in %s",
  1192.                         show_format(cur_format));
  1193.     }
  1194.  
  1195.     if (dpb->SYS) {
  1196.         if (Verb > 0) {
  1197.             printm(1,"CP/M already in image! Overwrite? ");
  1198.             if (!confirmed()) return 0;
  1199.         }
  1200.     }
  1201.  
  1202.     if (dpb->OFS < 2) {
  1203.         return errorf(FALSE,"Too few space for system (I need 2 "
  1204.                         "tracks, not %d)",dpb->OFS);
  1205.     }
  1206.  
  1207.     sysgen(arg[1]);
  1208.     return 0;
  1209. }
  1210.  
  1211.  
  1212. int cmd_type() {
  1213. /*  ^^^^^^^^
  1214. Puts the contents of a CP/M file to a pager [def], a file [-f] or stdout [-c].
  1215. */
  1216. char    outname[INPUTLEN];
  1217. char    tempname[INPUTLEN];
  1218. char    *cpmname;
  1219. char    optchar;
  1220. FILE    *outfile;
  1221. int    tempfile;
  1222. int    local_mode;
  1223. int    how=1;        /* 0=on stdout, 1=on pager, 2=on file */
  1224. int    counter=0;
  1225. int    i, r;
  1226. int    err;
  1227. uchar    *buf;
  1228. const char errmsg[] = "TYPE [-f | -c | -t | -b] <cmp-filename>";
  1229.  
  1230.     buf = block_buffer;    /* a shortcut */
  1231.  
  1232.     if (inactive()) return 0;
  1233.     if (nbof_args==0)       return cmd_error(errmsg);
  1234.  
  1235. /* parse options */
  1236.     opterr = 0;    /* no errormessages in getopt */
  1237.     optind = FIRST_OPTIND;
  1238.     local_mode = mode;
  1239.     while ((optchar=getopt(nbof_args+1,arg,"f:ctb"))!= EOF) {
  1240.         switch (optchar) {
  1241.         case 'f':    strcpy(outname,optarg);    how=2;    break;
  1242.         case 'c':    how=0;    break;
  1243.         case 't':    local_mode = M_TEXT;    break;
  1244.         case 'b':    local_mode = M_BIN;    break;
  1245.         case ':':
  1246.         case '?':    return cmd_error(errmsg);
  1247.         }
  1248.     }
  1249.  
  1250.     if (REMAINING_ARGS!=1) return cmd_error(errmsg);
  1251.  
  1252.     set_force_mode(9999,local_mode);
  1253.     cpmname = arg[optind];
  1254.  
  1255. /* prepare the output medium */
  1256.     switch (how) {
  1257.     case 0:        /* stdout */
  1258.         outfile=fdopen(1,"w");
  1259.         break;
  1260.     case 1:        /* pager */
  1261.         tmp_nam(outname);
  1262.         outfile = fopen(outname,"w");
  1263.         if (outfile==NULL) {
  1264.             return errorf(TRUE,"Cannot open temporary file \"%s\" "
  1265.                             "for writing ",outname);
  1266.         }
  1267.     case 2:        /* file */
  1268.         outfile = fopen(outname,"w");
  1269.         if (outfile==NULL) {
  1270.             return errorf(TRUE,"Cannot open \"%s\" for writing ",
  1271.                                     outname);
  1272.         }
  1273.     }
  1274.  
  1275.  
  1276. /* do the output */
  1277.     tmp_nam(tempname);
  1278.     err=get(cpmname,tempname);
  1279.     if (err==-1) {
  1280.         restore_force_mode();
  1281. /*        return errorf(FALSE,"\"%s\" not found",cpmname);*/
  1282.         return -1;
  1283.     }
  1284.  
  1285.     tempfile=open(tempname,O_RDONLY|O_BINARY);
  1286.     if (tempfile==-1) {
  1287.         errorf(TRUE,"I cannot read \"%s\"",tempname);
  1288.         restore_force_mode();
  1289.         return -1;
  1290.     }
  1291.  
  1292.  
  1293.     r=read(tempfile,buf,(dpb->BLS));
  1294.     if (local_mode==M_AUTO) {
  1295.         local_mode = detectmode((signed char*)buf,max((dpb->BLS),r));
  1296.     }
  1297.  
  1298.     while (r>0) {
  1299.         if (local_mode==M_TEXT) {
  1300.             for (i=0;i<(dpb->BLS);i++) {
  1301.                 err=putc(buf[i],outfile);
  1302.                 if (err<0) break;
  1303.             }
  1304.         } else {
  1305. /* filesize is a multiple of 16, because it's a multiple of 128 */
  1306.             for (i=0;i<(dpb->BLS);i+=16) {
  1307.                 err=fprintf(outfile,"%s\n",
  1308.                         show_hex(counter,buf+i,16));
  1309.                 if (err<0) break;
  1310.                 counter += 16;
  1311.             }
  1312.         }
  1313.         if (err<0) {
  1314.             close(tempfile);
  1315.             unlink(tempname);
  1316.             return errorf(TRUE,"");
  1317.         }
  1318.         r=read(tempfile,buf,(dpb->BLS));
  1319.     }
  1320.     putc(10,outfile);
  1321.  
  1322.     close(tempfile);
  1323.     unlink(tempname);
  1324.  
  1325.     fflush(outfile);
  1326.     if (how!=0) fclose(outfile);    /* do not close stdout */
  1327.     if (how==1) {
  1328.         if (pager(outname)) errorf(TRUE,"TYPE");
  1329.         unlink(outname);
  1330.     }
  1331.  
  1332.     restore_force_mode();
  1333.     return 0;
  1334. }
  1335.  
  1336.  
  1337. int cmd_user() {
  1338. /*  ^^^^^^^^ */
  1339. int    u;
  1340. const char errmsg[] = "\tUSER <userarea 0..15>\n\t<userarea>:";
  1341.     if (inactive()) return 0;
  1342.     if (nbof_args == 0) printm(0,"User is %d\n",cur_user);
  1343.     else if (nbof_args > 1) {
  1344.         return cmd_error(errmsg);
  1345.     } else {
  1346.         if (!isdigit(arg[1][0])) return cmd_error(errmsg);
  1347.         u=atoxi(arg[1]);
  1348.         if (u>255) return cmd_error("<userarea> must be < 256.");
  1349.         if (u>15) printm(4,"User numbers > 15 may cause trouble.\n");
  1350.         cur_user=u;
  1351.     }
  1352.     return 0;
  1353. }
  1354.  
  1355.  
  1356. int cmd_verbosity()  {
  1357. /*  ^^^^^^^^^^^^^ */
  1358. int    v;
  1359.     if (nbof_args>1) return cmd_error("VERBOSITY [<level -1..19>]");
  1360.  
  1361.     if (nbof_args==0)
  1362.         printm(0,"Verbosity is %d\n",Verb);
  1363.     else {
  1364.         v = atoxi(arg[1]);
  1365.         printm(2,"Verbosity set to %d\n",v);
  1366.         Verb = v;
  1367.     }
  1368.     return 0;
  1369. }
  1370.  
  1371.  
  1372. /*********************************************************************
  1373.               User Interface
  1374.  *********************************************************************/
  1375.  
  1376. #define NBOFCMDS    40
  1377. struct {
  1378.     char    *name;
  1379.     int    (*proc)();
  1380.     } command[NBOFCMDS] = {
  1381.         {"!",        cmd_spawn },
  1382.         {"?",        cmd_help },
  1383.         {"attrib",    cmd_attrib },
  1384.         {"bye",        cmd_exit },
  1385.         {"cd",        cmd_lcd },
  1386.         {"close",    cmd_close },
  1387.         {"cls",        cmd_cls },
  1388.         {"copy",    cmd_copy },
  1389.         {"comment",    cmd_comment},
  1390.         {"del",        cmd_era },
  1391.         {"dir",        cmd_dir },
  1392.         {"dira",    cmd_dira },
  1393.         {"dpb",        cmd_dpb },
  1394.         {"dump",    cmd_dump },
  1395.         {"echo",    cmd_echo },
  1396.         {"era",        cmd_era },
  1397.         {"exit",    cmd_exit },
  1398.         {"force",    cmd_force },
  1399.         {"format",    cmd_new },
  1400.         {"get",        cmd_get },
  1401.         {"help",    cmd_help },
  1402.         {"lcd",        cmd_lcd },
  1403.         {"ldir",    cmd_ldir },
  1404.         {"map",        cmd_map },
  1405.         {"mget",    cmd_mget },
  1406.         {"mode",    cmd_mode },
  1407.         {"mput",    cmd_mput },
  1408.         {"new",        cmd_new },
  1409.         {"open",    cmd_open },
  1410.         {"page",    cmd_page },
  1411.         {"prompt",    cmd_prompt },
  1412.         {"put",        cmd_put },
  1413.         {"quit",    cmd_exit },
  1414.         {"ren",        cmd_ren },
  1415.         {"source",    cmd_source },
  1416.         {"stat",    cmd_stat },
  1417.         {"sysgen",    cmd_sysgen },
  1418.         {"type",    cmd_type },
  1419.         {"user",    cmd_user },
  1420.         {"verbosity",    cmd_verbosity},
  1421.     };
  1422.  
  1423.  
  1424. int execute_one_cmd (char *input) {
  1425. /*  ^^^^^^^^^^^^^^^
  1426. Execute a single command. */
  1427. char    buffer[INPUTLEN];
  1428. char    userbuffer[INPUTLEN];
  1429. char    *line;
  1430. char    spawn[] = "!";
  1431. int    i;
  1432.  
  1433.     Break_Wish = FALSE;
  1434.     strncpy(buffer,input,INPUTLEN-1);
  1435. #if DOS
  1436.     line=strchr(buffer,13);
  1437.     if (line) *line=0;
  1438. #endif
  1439.     line=buffer;
  1440.     nbof_args=0;
  1441.     if (!line) return 0;
  1442.     for (;;) {
  1443.         while ((*line==' ')||(*line=='\n')||(*line=='\t'))
  1444.             line++;                /*skip white*/
  1445.         if (*line==0) break;
  1446.         if (*line=='#') break;            /*comment*/
  1447.         if (nbof_args==0) {
  1448.             if (*line=='!') {        /*! special*/
  1449.                 arg[0]=spawn;
  1450.                 line++;
  1451.                 nbof_args++;
  1452.                 continue;
  1453.             }
  1454.         }
  1455.         arg[nbof_args++] = line;        /*remember arg*/
  1456.  
  1457.         if (*line=='"') {            /* quoted string */
  1458.             arg[nbof_args-1]++;        /* skip quote */
  1459.             line++;
  1460.             while (*line!='"' && *line!=0) line ++;
  1461.             if (*line==0) {
  1462.                 return errorf(FALSE,"Missing closing quote!");
  1463.             }
  1464.             *line++ = 0;            /* replace quote */
  1465.         } else {
  1466.             while (*line!=' ' && *line!='\n' && *line!='\t'
  1467.               && *line!=0)
  1468.                 line++;
  1469.             if (*line==0) break;
  1470.             else *line++=0;            /*set end-of-arg*/
  1471.         }
  1472.  
  1473.     }
  1474.     nbof_args--;
  1475.  
  1476.  
  1477.     if (nbof_args==-1) {
  1478.         nbof_args=0;
  1479.         return 0;
  1480.     }
  1481.  
  1482.     lower(arg[0]);
  1483.  
  1484. /* shortcut for USER command */
  1485.     if (nbof_args==0 && arg[0][strlen(arg[0])-1]==':') {
  1486.         sprintf(userbuffer,"user %s",arg[0]);
  1487.         execute_one_cmd(userbuffer);
  1488.         return 0;
  1489.     }
  1490.  
  1491.     for (i=0;i<NBOFCMDS;i++) {
  1492.         if (strcmp(command[i].name,arg[0])==0) {
  1493.             (command[i].proc)();
  1494.             return 0;
  1495.         }
  1496.     }
  1497.     return errorf(FALSE,"%s: Unknown Command!",arg[0]);
  1498. }
  1499.  
  1500.  
  1501. int execute_cmd (char *input) {
  1502. /*  ^^^^^^^^^^^
  1503. Execute commands separated by ";". */
  1504. char    *p;
  1505.     for (;;) {
  1506.         p = strchr(input,';');
  1507.         if (p) *p=0;
  1508.         execute_one_cmd(input);
  1509.         if (!p) break;
  1510.         input = p+1;
  1511.     }
  1512.     return 0;
  1513. }
  1514.  
  1515. /******
  1516.   main
  1517.  ******/
  1518.  
  1519. void init(char *argv0) {
  1520. /*   ^^^^ */
  1521.  
  1522. char    *p;
  1523.  
  1524. #if USE_READLINE && UNIX
  1525. int    rl_bind_key();        /* where is the prototype??? */
  1526. #endif
  1527.     os_init();
  1528.     strcpy(prompt,"cpcfs> ");
  1529.     *disk_header.tag=0;
  1530. /*    cur_trk = -1;    set in fs.c */
  1531.     DPB_store[USER_DPB] = DPB_store[DATA_DPB]; /* set default user DPB */
  1532.     pagelen=25;
  1533.     disable_break();
  1534.     Break_Wish = FALSE;
  1535.     mode = M_AUTO;
  1536.     force = FALSE;
  1537. #if DOS
  1538.     _fmode = O_BINARY;
  1539. #endif
  1540. #if USE_READLINE && UNIX
  1541. /* configure GNU readline */
  1542.     rl_bind_key ('\t', rl_insert);
  1543. #endif
  1544.  
  1545. /* works only for DOS */
  1546.     strcpy(installpath,argv0);
  1547.     p = strrchr(installpath,DIRSEPARATOR);
  1548.     if (p!=NULL) *(++p) = 0;
  1549.     else         installpath[0] = 0;
  1550. }
  1551.  
  1552.  
  1553. int execute_file (char *name) {
  1554. /*  ^^^^^^^^^^^^ */
  1555. FILE    *file;
  1556. char    line[INPUTLEN];
  1557.  
  1558.     if ((file=fopen(name,"r")) == NULL) {
  1559.         return errorf(TRUE,"\"%s\" not found",name); 
  1560.     }
  1561.     while (fgets(line,INPUTLEN,file))
  1562.         execute_cmd(line);
  1563.     fclose(file);
  1564.     return 0;
  1565. }
  1566.  
  1567.  
  1568. void read_cfg_file() {
  1569. /*   ^^^^^^^^^^^^^ */
  1570.  
  1571. char    name[INPUTLEN];
  1572. int    notfound;
  1573.  
  1574.     strcpy(name,CONFIGNAME);
  1575.     notfound = access(name,R_OK);
  1576.     if (notfound) {
  1577.         strcpy(name,installpath);
  1578.         strcat(name,CONFIGNAME);
  1579.         notfound = access (name,R_OK);
  1580.         if (notfound)  {
  1581.             return;
  1582.         }
  1583.     }
  1584.     execute_file(name);
  1585. }
  1586.  
  1587.  
  1588. void interaction (char *argv0) {
  1589. /*   ^^^^^^^^^^^ */
  1590. #if USE_READLINE && UNIX
  1591. char    prompt_buf[INPUTLEN];
  1592. char    *line;
  1593. #elif USE_READLINE && DOS
  1594. char    prompt_buf[INPUTLEN];
  1595. char    line[INPUTLEN];
  1596. int    len;
  1597. #else
  1598. char    line[INPUTLEN];
  1599. #endif
  1600.  
  1601.     read_cfg_file();
  1602.  
  1603.     setjmp(break_entry);
  1604.     for (;;) {
  1605. #if USE_READLINE && UNIX
  1606.         *prompt_buf = 0;
  1607.         if (Verb >= 1) expand_percent(prompt,prompt_buf,INPUTLEN);
  1608.         line = readline(prompt_buf);
  1609.         if (line==NULL) {
  1610.             printm(3,"[Quit]\n");
  1611.             execute_cmd("exit");
  1612.         }
  1613.         if (line && *line)    add_history(line);
  1614.         execute_cmd (line);
  1615.         free(line);
  1616. #elif USE_READLINE && DOS
  1617.         *prompt_buf = 0;
  1618.         if (Verb >= 1) expand_percent(prompt,prompt_buf,INPUTLEN);
  1619.         printf("%s",prompt_buf);
  1620.         *line=0;
  1621.         len = inputs(line,INPUTLEN-strlen(prompt_buf)-1,-1);
  1622.         if (len==-2) {
  1623.             printm(3,"[Quit]\n");
  1624.             execute_cmd("exit");
  1625.         }
  1626.         if (line && *line)    add_history(line);
  1627.         execute_cmd(line);
  1628. #else  /* ! USE_READLINE */
  1629.         echom(1,prompt);
  1630.         execute_cmd(gets(line));
  1631. #endif
  1632.     }
  1633. }
  1634.  
  1635.  
  1636.  
  1637. void usage (bool err) {
  1638. /*   ^^^^^ */
  1639. char    buf[INPUTLEN];
  1640.     if (err) {
  1641.         printm(1,"Error in command line!\n\n");
  1642.     } else {
  1643.         printm(1,"CPCfs - CPCEmu Filessystem Maintenance\n");
  1644.         expand_percent("%V",buf,INPUTLEN);
  1645.         printm(1,"   %s\n\n",buf);
  1646.         printm(1,"SYNOPSIS:\n");
  1647.         printm(1,"   cpcfs                  Enter interactive mode\n");    
  1648.         printm(1,"or ");
  1649.     }
  1650.     printm(1,"cpcfs [<imagefile>] <command>...\n");
  1651.     printm(1,"where\n");
  1652.     printm(1,"   <imagefile> is implicitly opened\n");
  1653.     printm(1,"   <command> = -d   dir     Directory (default command)\n");
  1654.     printm(1,"               -s   stat    Statistics\n");
  1655.     printm(1,"               -g   get     Get a file\n");
  1656.     printm(1,"               -p   put     Put a file\n");
  1657.     printm(1,"               -mg  mget    Get many files\n");
  1658.     printm(1,"               -mp  mput    Put many files\n");
  1659.     printm(1,"               -nX  new     Create new image (X=dsv, Data, "
  1660.                             "System, or Vortex)\n");
  1661.     printm(1,"               -f   force   Force overwrite, if file exists\n");
  1662.     printm(1,"               -t   text    ASCII Mode\n");
  1663.     printm(1,"               -b   bin     Binary Mode\n");
  1664.     printm(1,"               -e           Execute arbitrary commands, "
  1665.                             "separated by ';'\n");
  1666.     printm(1,"               -x   source  Execute commands from file\n");
  1667.     printm(1,"               -h, -?       This help\n");
  1668. }
  1669.  
  1670.  
  1671.  
  1672.  
  1673. void ui_main (int argc, char **argv) {
  1674. /*   ^^^^^^^
  1675. Main function for CPCfs based on Text User Interface */
  1676.  
  1677. char    line[INPUTLEN];
  1678. int    i;
  1679. bool    more_switches = TRUE;
  1680.  
  1681.     init(argv[0]);
  1682.  
  1683. /* no arguments => interactive mode */
  1684.     if (argc==1) {
  1685.         Interactive = TRUE;
  1686.         interaction(argv[0]);
  1687.         exit(0);
  1688.     }
  1689.  
  1690.     Interactive = FALSE;
  1691. /* only filename => dir all */
  1692.     if ((argc==2) && argv[1][0]!='-') {
  1693.         strcpy(line,"open "); strcat(line,argv[1]);
  1694.         if (execute_cmd(line))        exit(1);
  1695.         if (execute_cmd("dir *:*.*"))    exit(1);
  1696.         exit(0);
  1697.     }
  1698.  
  1699. /* execute commandline */
  1700.     strcpy(line,"open");    /* if no command is given */
  1701.     for (i=1;i<argc;i++) {
  1702.         if (more_switches && argv[i][0]=='-') {
  1703.             if (i>1) {
  1704.                 if (execute_cmd(line)) {
  1705.                     exit(1);
  1706.                 }
  1707.             }
  1708.             *line = 0;
  1709.             switch (tolower(argv[i][1])) {
  1710.             case 'g': strcpy(line,"get"); break;
  1711.             case 'p': strcpy(line,"put"); break;
  1712.             case 'f': strcpy(line,"force"); break;
  1713.             case 't': strcpy(line,"mode text"); break;
  1714.             case 'b': strcpy(line,"mode bin"); break;
  1715.             case 'm':
  1716.                 switch (tolower(argv[i][2])) {
  1717.                 case 'g': strcpy(line,"mget"); break;
  1718.                 case 'p': strcpy(line,"mput"); break;
  1719.                 default:  usage(TRUE); exit(1);
  1720.                 }
  1721.                 break;
  1722.             case 'n':
  1723.                 switch (tolower(argv[i][2])) {
  1724.                 case 'd': strcpy(line,"new -d"); break;
  1725.                 case 's': strcpy(line,"new -s"); break;
  1726.                 case 'v': strcpy(line,"new -v"); break;
  1727.                 default:  usage(TRUE); exit(1);
  1728.                 }
  1729.                 break;
  1730.             case 's': strcpy(line,"stat"); break;
  1731.             case 'e': more_switches = FALSE; break;
  1732.             case 'd': strcpy(line,"dir"); break;
  1733.             case 'x': strcpy(line,"source"); break;
  1734.             case 'h':
  1735.             case '?': usage(FALSE); exit(0);
  1736.             default:  usage(TRUE); exit(1);
  1737.             }
  1738.         } else {
  1739.             strcat(line," ");
  1740.             strcat(line,argv[i]);
  1741.         }
  1742.     }
  1743.     execute_cmd(line);
  1744.     execute_cmd("close");
  1745. }
  1746.